<?php

/**
* alltosun.com 文件上传控制器 file_uploader.php
* ============================================================================
* 版权所有 (C) 2009-2012 北京互动阳光科技有限公司，并保留所有权利。
* 网站地址: http://www.alltosun.com
* ----------------------------------------------------------------------------
* 许可声明：这是一个开源程序，未经许可不得将本软件的整体或任何部分用于商业用途及再发布。
* ============================================================================
* $Author: 钱有明 (qianym@alltosun.com) $
* $Date: 2012-9-28 下午4:21:19 $
* $Id: file_uploader.php 28573 2014-02-15 11:48:20Z qianym $
*/

/**
 * @tutorial
 * 如果前端上传工具不是flash，且自带的上传名称也不为Filedata的话，必须传入file_field值
 * 如果需要生成缩略图，前台上传工具必须通过POST或者GET方法传入res_name，否则只保存原图
 * @return 默认返回id|path的格式，如果前端上传工具需要接受特定的返回数据，可以在output方法中定义
 */
class Action
{
    private $file_field;      // 上传时用于接收文件的key
    private $source;          // 上传工具

    private $user_id;         // 上传者
    private $company_id;      // 企业
    private $app_id;          // 应用
    private $file_id;         // 文件id（注意区分与文件版本id的差别）
    private $dir_id;          // 所属目录

    private $res_name;        // 资源(用来生成缩略图)
    private $res_id;        // 资源id

    private $app_res_name;    // 资源(用来生成文件与app的关联关系)
    private $app_res_id;
    private $category_id;     // 缩略图category
    private $type;            // 缩略图类型(small, middle...)

    private $attachment_type; // 附件类型

    private $snapshot_name;   // 截图上传

    // private $max_size_config = array('xheditor'=>122880);
    private $max_size;        // 文件大小限制
    private $allow_type_key;

    private $file_name;

    function __construct()
    {
        // 如果Request中有file_field的话，使用Request中的file_field，否则使用flash传来的默认的Filedata
        // xheditor上传使用的filedata
        // ui.fileuploader使用的flash，默认为Filedata
        $this->file_field    = Request::getParam('file_field', 'Filedata');
        $this->source        = Request::getParam('source', 'ajaxuploader');
        $this->file_id       = Request::getParam('file_id', 0);
        $this->dir_id        = Request::getParam('dir_id', 0);
        $this->type          = Request::getParam('type');
        $this->res_name      = Request::getParam('res_name', 'file');
        $this->res_id        = Request::getParam('res_id', 0);
        $this->app_res_name  = Request::getParam('app_res_name');
        $this->app_res_id    = Request::getParam('app_res_id', 0);
        $this->snapshot_name = Request::getParam('snapshot_name');
        $this->category_id   = Request::getParam('category_id', 0);

        $this->user_id       = user_helper::get_user_id();
        $this->company_id    = company_helper::get_company_id();

        $this->max_size      = isset($this->max_size_config[$this->source]) ? $this->max_size_config[$this->source] : 0;
        $this->allow_type_key = Request::getParam('key', 'attachment');
    }

    function __call($action = '', $params = array())
    {
        if ($this->user_id == 16 || $this->user_id == 3) {
            //var_dump($_FILES, 'qian11', $_SERVER);
            //exit;
        }
        /* if (empty($this->user_id)) {
            $this->output('上传失败，请登录后重试。');
        } */

        if (isset($_FILES['xfile'])) {
            $this->file_field = 'xfile';
        }

        // html5上传
        $this->html5_upload();

        if (empty($_FILES[$this->file_field])) {
            $this->output('请选择您要上传的文件。');
        }

        if ($this->snapshot_name) {
            $_FILES[$this->file_field]['name'] = $this->snapshot_name;
        }

        // php.ini限制的post大小
        $POST_MAX_SIZE = ini_get('post_max_size');
        $unit = strtoupper(substr($POST_MAX_SIZE, -1));
        $multiplier = ($unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1)));

        if ((int)$_SERVER['CONTENT_LENGTH'] > $multiplier * (int)$POST_MAX_SIZE && $POST_MAX_SIZE) {
            header("HTTP/1.1 500 Internal Server Error"); // This will trigger an uploadError event in SWFUpload
            $this->output('对不起，上传文件超过服务器限制大小。');
        }

        // 上传配置
        $file_field  = $this->file_field;
        $upload_path = UPLOAD_PATH;

        $this->file_name = $_FILES[$file_field]['name'];
        //var_dump($_FILES);exit;

        // 上传验证（限制的文件大小，与类型的验证）
        if ($this->allow_type_key == 'attachment') {
            // 附件允许的检测
            $failed_msg = check_upload($_FILES[$file_field], $this->max_size, 1);
            //$allow_type  = Config::get('allow_type');
        } else {
            // 其它为图片
            // 图片的检测
            $failed_msg = check_upload($_FILES[$file_field], $this->max_size);
            //$allow_type  = Config::get('allow_image_type');
        }

        if (!empty($failed_msg)) {
            $this->output($failed_msg);
            exit(0);
        }

        // 上传
        /*$uploadr = new Uploadr($upload_path, $allow_type);
        try {
            $file_path = $uploadr->uploadFile($_FILES[$file_field]['tmp_name']);
        } catch (Exception $e) {
            $analyze = new getid3();
            $analyze = $analyze->analyze($_FILES[$file_field]['tmp_name']);
            //an_dump($analyze);exit(0);
            //$this->output($e->getMessage());
            $this->output('文件保存失败，请检查文件！'.$e->getMessage().an_dump($analyze));
        }*/


        $file_extension_name = pathinfo($_FILES[$file_field]['name'], PATHINFO_EXTENSION);
        if(ONDEV) {
            $file_path = $this->_upload($_FILES[$file_field]['tmp_name'], $file_extension_name);
        } else {
            $return_image_data = aliysso_helper::upload_file($_FILES[$file_field], false);
            $file_path = $return_image_data['file_path'];
        }
        if (empty($file_path)) {
            $this->output('文件保存失败，请重试');
        }

        // 附件类型
        $this->attachment_type = get_attachment_type($file_path);
        // 缩略图
        if ($this->attachment_type == 1) {
             make_thumb($file_path, $this->res_name);
            if ($this->res_name == 'file') {
                make_thumb($file_path, 'file_cut', 0, 'small');
            }
        }

        if ($this->source != 'xheditor') {

            // 插入数据库
            $version_id = 0;
            //$file_version_info = _model('file_version')->read(array('path'=>$file_path));
            //if (!empty($file_version_info) && 1 != 1) {
            if (1 != 1) {
                // 如果同一张图片在不同模型中使用，这样处理会导致返回的缩略图比例只是第1个模型产生的
                // 可采用解决方案：图片存放名称不用md5唯一值，改为当前时间+计数，已在Uploadr.php采用该方案
                //$version_id = $file_version_info['id'];
            } else {
                // 上传图片，并且生成协作关系
                $file_name =  htmlspecialchars($_FILES[$file_field]['name'], ENT_NOQUOTES);
                if ($this->snapshot_name) {
                    $file_name = $this->snapshot_name;
                }

                $attachment_info = array(
                                'file_name'      => $file_name,
                                'path'       => $file_path,
                                'user_id'    => $this->user_id,
                                'type'       => $this->attachment_type,
                                'size'       => $_FILES[$file_field]['size']
                );

                $this->file_id = _model('attachment')->create($attachment_info);
                if ($this->res_name && $this->res_id) {
                    attachment_helper::add_attachment_relation($this->res_name, $this->res_id, $this->file_id);
                }
                if ($this->source == 'ueditor') {
                    attachment_helper::add_attachment_relation('ueditor_file', 0, $this->file_id);
                }

            }

            if (empty($this->file_id)) {
                $this->output('数据写入失败，请重试');
            }
        }

        $output = array('id'=>$this->file_id, 'file_path'=>$file_path, 'small_path'=>'');
        if ($this->attachment_type == 1) {
            $output['small_path'] = _image($file_path, 'small');
        }

        /* if ($this->source == 'ajaxuploader') {
            $output['id'] = $this->file_id;
        } */

        $this->output($output, FALSE);
    }

    /**
     * 转换html5的上传
     * @return bool
     */
    private function html5_upload()
    {
        if (!isset($_SERVER['HTTP_CONTENT_DISPOSITION'])) {
            return FALSE;
        }
        if (!preg_match('/attachment;\s+name="(.+?)";\s+filename="(.+?)"/i', $_SERVER['HTTP_CONTENT_DISPOSITION'], $info)) {
            return FALSE;
        }

        $temp_name = tempnam(sys_get_temp_dir(), 'html5').mt_rand();

        file_put_contents($temp_name, file_get_contents("php://input"));

        $_FILES[$info[1]] = array(
            'name'     => $info[2],
            'tmp_name' => $temp_name,
            'size'     => filesize($temp_name),
            'type'     => '',
            'error'    => 0
        );

        return TRUE;
    }

    /**
     * 处理输出数据，可按照前端不同上传工具返回不同数据结构
     * @param $string 输出信息
     * @param $error 输出信息是否为错误，默认为TRUE
     */
    private function output($info, $error = TRUE)
    {
        $source      = $this->source;
        $res_name    = $this->res_name;
        $category_id = $this->category_id;
        $output      = '';

        if ($source == 'xheditor') {
            /**
             * 1,上传文件域名字为：filedata
             * 2,返回结构必需为json，并且结构如下：{"err":"","msg":"200906030521128703.gif"}
             * 若上传出现错误，请将错误内容保存在err变量中；若上传成功，请将服务器上的绝对或者相对地址保存在msg变量中。
             * 编辑器若发现返回的err变量不为空，则弹出窗口显示返回的错误内容。
             * @var array('err'=>'', 'msg'=>'');
             */
            $xheditor_data = array('err'=>'', 'msg'=>'');
            if ($error) {
                $xheditor_data['err'] = $info;
            } else {
                // 只有最后才返回数据，数据格式为id|path
                // 2010-10-27 gaojj 编辑器上传图片返回全路径，方便内容数据同步到其他网站
                // 不取gif缩略图，不然不会动
                $ex = substr($info['file_path'], strripos($info['file_path'], '.')+1);
                $is_tmp = 0;
                if ($this->source != 'xheditor') {
                    $is_tmp = 1;
                }
                if ($this->type == 'big' && stripos($ex, 'gif') === FALSE) {
                    $path = SITE_URL._image($info['file_path'], $this->type);
                } else {
                    $path = SITE_URL._image($info['file_path']);
                }

                // 若返回的地址最前面为半角的感叹号：“!”，表示为立即上传模式，
                // 上传成功后不需要点“确定”按钮，随后自动插入到编辑器内容中。
                if (Request::getParam('immediate', 0) == 1) {
                    $path = '!'.$path;
                }

                $msgs = array(
                    'id'  => $info['id'],
                    'url' => $path,
                    'file_name'=> $this->file_name
                );
                //返回id+path
                $xheditor_data['msg'] = $msgs;
            }
            $output = json_encode($xheditor_data);
        } elseif ($source == 'ajaxuploader') {
            // ajax上传返回array('info'=>'ok', 'path'=>'', 'small'=>'', 'middle'=>'',...);
            $json = array();
            if ($error) {
                $json['info'] = $info;
            } else {
                $json['info'] = 'ok';
                // _image处理后返回的数据已经含有上传文件目录路径，不能存入数据库，用file_path存入
                // $json['path'] = _image($info['file_path']);
                $json['id']        = $info['id'];
                $json['file_path'] = $info['file_path'];
                $json['file_name']     = $this->file_name;

                if(ONDEV) {
                    $thumb_set = get_res_thumb($res_name, $category_id);
                } else {
                    $thumb_set = aliysso_helper::get_res_thumb($res_name);
                }

                if (!empty($thumb_set)) {
                    foreach ($thumb_set as $k=>$v) {
                        if ($this->attachment_type == 1) {
                            $json[$k] = _image($info['file_path'], $k);
                        }
                    }
                }
            }
            $output = json_encode($json);
        } elseif ($source == 'ueditor'){
            $url = ''; $file_name = ''; $original = ''; $state = '';

            if ($error) {
                $state = $info;
            } else {
                $file_info = _model('attachment')->read($info['id']);

                if ($file_info) {
                    $state    = 'SUCCESS';
                    $url      = _image($file_info['path']);
                    $file_name    = $file_info['file_name'];
                    $original = $file_info['file_name'];
                } else {
                    $state = '文件读取失败';
                }
            }

            $json = array(
                'url'      =>$url,   //保存后的文件路径
                'title'    =>$file_name,   //文件描述，对图片来说在前端会添加到file_name属性上
                'original' =>$original,   //原始文件名
                'state'    =>$state  //上传状态，成功时返回SUCCESS,其他任何值将原样返回至图片上传框中
            );
            $output = json_encode($json);
        }else {
            // 前端flash无法处理JSON或者XML，返回id|path的格式
            if ($error) {
                $output = $info;
            } else {
                $output = $info['id'].'|'.$info['file_path'].'|'.$info['small_path'];
            }
        }

        echo $output;
        exit(0);
    }

    // 上传文件
    private function _upload($file, $ext = 'jpg')
    {
        $time = time();
        if ($this->source == 'xheditor') {
            $folder = UPLOAD_PATH.'/uploadtmp'.date('/Y/m/d', $time);
        } else {
            $folder = UPLOAD_PATH.date('/Y/m/d', $time);
        }

        if (!file_exists($folder) && !@mkdir($folder, 0777, true)) {
            return false;
        }

        $allow_image_type = Config::get('allow_image_type');
        // 如果是图片的话，则按当前时间+文件大小+随机数（用于区分同一秒多个进程上传不同文件）存放文件
        // 这样可以让不同模型使用同一张图片可以生成不同缩略图

        if (in_array(strtolower($ext), $allow_image_type)) {
            static $count = 1;

            // u为microseconds，> PHP 5.2.2
            if (version_compare(PHP_VERSION, '5.2.2') >= 0) {
                $current_time = date('YmdHisu', $time);
            } else {
                $current_time = date('YmdHis', $time);
            }

            $random = mt_rand(0, 100);

            $target = $folder.'/'.$current_time.'_'.$count.'_'.filesize($file).'_'.$random.'.'.$ext;

            $count++;
        } else {
            // 同一文件只上传一次
            $target = $folder.'/'.md5_file($file).filesize($file).'.'.$ext;
        }
        $target = trim($target, '.');
        /* if ($this->user_id == 16) {
            var_dump($ext, $target);
            exit;
        } */

        if (!file_exists($target)) {
            if (!rename($file, $target)) {
                return false;
            }
        }

        return substr($target, strlen(UPLOAD_PATH));
    }
}
?>